/*
 *  ifxcursor.hpp - Informix dbExpress cursor class
 *
 *    Copyright (c) 2001-2006, Luxena Software Company. All rights reserved.
 *
 *  Purpose:
 *
 */

#ifndef __IFXCURSOR_HPP__
#define __IFXCURSOR_HPP__

#ifndef __cplusplus
#error This header requires a C++ compiler ...
#endif

#include <list>
#include <sqlda.h>
#include <sqlhdr.h>
#include "dbxpress.hpp"
#include "ifxvariable.hpp"
#include "ifxcommand.hpp"


/////////////////////////////////////////////////////////////////////////////
// CColumnDescription

class CColumnDescription
{
public:
	void describe (pCHAR name, DataType dataType, UINT32 length,
		INT16 precision, INT16 scale, BOOL isNullable, BOOL isAutoIncrement);

	UINT16 getNameLength () const { return strlen(_name); }
	pCHAR getName () const { return _name; }
	const DataType& getDataType () const { return _dataType; }
	UINT32 getLength () const { return _length; }
	void setLength (UINT32 value) { _length = value; }
	INT16 getPrecision () const { return _precision; }
	void setPrecision (INT16 value) { _precision = value; }
	INT16 getScale () const { return _scale; }
	BOOL isNullable () const { return _isNullable; }
	BOOL isAutoIncrement () const { return _isAutoIncrement; }
	BOOL isReadOnly () const { return 0; }
	BOOL isSearchable () const { return 0; }
	BOOL isBlobSizeExact () const { return 1; }

private:
	pCHAR _name;
	DataType _dataType;
	UINT32 _length;
	INT16 _precision;
	INT16 _scale;
	BOOL _isNullable;
	BOOL _isAutoIncrement;
};


/////////////////////////////////////////////////////////////////////////////
// CInformixCursor - SQLCursor implementation for Informix

class CInformixCursor : public CErrorHandlingImpl< CUnknownImpl<SQLCursor> >,
	private IFetchSubject, private IDatabaseChangeObserver
{
public:
	CInformixCursor (CInformixCommand *command);
	virtual ~CInformixCursor ();

	CInformixConnection * getConnection ();
	CCallback * getCallback ();
	int2 getColumnCount ();
	CInformixVariable& getColumn (int2 number);
	CColumnDescription& getDescription (int2 number);
	bool isOpened ();
	virtual void setErrorMessage (const char* errorMessage);

// SQLCursor
	SQL_METHOD setOption (eSQLCursorOption eCurOption, INT32 lValue);
	SQL_METHOD getOption (eSQLCursorOption eCurOption, pINT32 plValue, INT16 iMaxLength, pINT16 piLength);
	SQL_METHOD getColumnCount (pUINT16 puColumns);
	SQL_METHOD getColumnNameLength (UINT16 uColumnNumber, pUINT16 puLen);
	SQL_METHOD getColumnName (UINT16 uColumnNumber, pCHAR pColumnName);
	SQL_METHOD getColumnType (UINT16 uColumnNumber, pUINT16 puLogType, pUINT16 puSubType);
	SQL_METHOD getColumnLength (UINT16 uColumnNumber, pUINT32 pulLength);
	SQL_METHOD getColumnPrecision (UINT16 uColumnNumber, pINT16 piPrecision);
	SQL_METHOD getColumnScale (UINT16 uColumnNumber, pINT16 piScale);
	SQL_METHOD isNullable (UINT16 uColumnNumber, pBOOL pbNullable);
	SQL_METHOD isAutoIncrement (UINT16 uColumnNumber, pBOOL pbAutoIncrement);
	SQL_METHOD isReadOnly (UINT16 uColumnNumber, pBOOL pbReadOnly);
	SQL_METHOD isSearchable (UINT16 uColumnNumber, pBOOL pbSearchable);
	SQL_METHOD isBlobSizeExact (UINT16 uColumnNumber, pBOOL pbBlobExactSize);
	SQL_METHOD next ();
	SQL_METHOD getString (UINT16 uColumnNumber, pCHAR pData, pBOOL pbIsNull);
	SQL_METHOD getShort (UINT16 uColumnNumber, pINT16 pData, pBOOL pbIsNull);
	SQL_METHOD getLong (UINT16 uColumnNumber, pINT32 pData, pBOOL pbIsNull);
	SQL_METHOD getDouble (UINT16 uColumnNumber, pDFLOAT pData, pBOOL pbIsNull);
	SQL_METHOD getBcd (UINT16 uColumnNumber, pFMTBcd pData, pBOOL pbIsNull);
	SQL_METHOD getTimeStamp (UINT16 uColumnNumber, pCTIMESTAMP pData, pBOOL pbIsNull);
	SQL_METHOD getTime (UINT16 uColumnNumber, pINT32 pData, pBOOL pbIsNull);
	SQL_METHOD getDate (UINT16 uColumnNumber, pINT32 pData, pBOOL pbIsNull);
	SQL_METHOD getBytes (UINT16 uColumnNumber, pBYTE pData, pBOOL pbIsNull);
	SQL_METHOD getBlobSize (UINT16 uColumnNumber, pUINT32 pulLength, pBOOL pbIsNull);
	SQL_METHOD getBlob (UINT16 uColumnNumber, pVOID pData, pBOOL pbIsNull, UINT32 ulLength);

private:
	void setResourceDefaults ();
	void open ();
	void initializeDataArea ();
	void initializeColumns ();
	void close ();
	void freeResources ();

	CInformixCommand *_command;
	ifx_cursor_t *_handle;
	ifx_sqlda_t *_sqlda;
	CInformixVariable *_variables;
	CColumnDescription *_descriptions;

// IFetchSubject
	virtual void attach (Observer observer);
	virtual void notify ();
	typedef std::list<Observer> FetchObservers;
	FetchObservers *_fetchObservers;

// IDatabaseChangeObserver
	virtual void databaseChanged ();
};

class CInformixTrimingCursor : public CInformixCursor
{
public:
	CInformixTrimingCursor (CInformixCommand *command) : CInformixCursor(command) {}
	SQL_METHOD getString (UINT16 uColumnNumber, pCHAR pData, pBOOL pbIsNull);
};


/////////////////////////////////////////////////////////////////////////////
// CInformixColumnFactory

class CInformixColumnFactory
{
public:
	struct CreateValueArgs
	{
		int4 length;
		int4 blobSize;
		IFetchSubject *fetchSubject;
	};

	typedef CInformixAbstractValue * (*CreateValueFunc) (const CreateValueArgs& args);

	class DescribeArgs
	{
	public:
		CInformixTypesMapping *mapping;
		int2 type;
		int4 length;
		char *name;
		int4 xid;
		char *typeName;
		bool isNullable () const;
		CColumnDescription *description;
		CInformixAbstractValue * createValue (const CreateValueArgs& args) const;
	private:
		CreateValueFunc createValueFunc;
		friend class CInformixColumnFactory;
	};

	static void describe (DescribeArgs& args);

private:
	static void decodeDecimalLength(int4& length, INT16& precision, INT16& scale);

	static void describeUnknown (DescribeArgs& args);
	static CInformixAbstractValue * createUnknownValue (const CreateValueArgs& args);

	static void describeChar (DescribeArgs& args);
	static CInformixAbstractValue * createCharValue (const CreateValueArgs& args);

	static void describeSmallInt (DescribeArgs& args);
	static CInformixAbstractValue * createSmallIntValue (const CreateValueArgs& args);

	static void describeInteger (DescribeArgs& args);
	static CInformixAbstractValue * createIntegerValue (const CreateValueArgs& args);

	static void describeFloat (DescribeArgs& args);
	static CInformixAbstractValue * createFloatValue (const CreateValueArgs& args);

	static void describeSmallFloat (DescribeArgs& args);
	static CInformixAbstractValue * createSmallFloatValue (const CreateValueArgs& args);

	static void describeDecimal (DescribeArgs& args);
	static CInformixAbstractValue * createDecimalValue (const CreateValueArgs& args);

	static void describeSerial (DescribeArgs& args);
	static CInformixAbstractValue * createSerialValue (const CreateValueArgs& args);

	static void describeDate (DescribeArgs& args);
	static CInformixAbstractValue * createDateValue (const CreateValueArgs& args);

	static void describeMoney (DescribeArgs& args);
	static CInformixAbstractValue * createMoneyValue (const CreateValueArgs& args);

	static void describeDateTime (DescribeArgs& args);
	static CInformixAbstractValue * createDateTimeValue (const CreateValueArgs& args);

	static void describeBytes (DescribeArgs& args);
	static CInformixAbstractValue * createBytesValue (const CreateValueArgs& args);

	static void describeText (DescribeArgs& args);
	static CInformixAbstractValue * createTextValue (const CreateValueArgs& args);

	static void describeVarChar (DescribeArgs& args);
	static CInformixAbstractValue * createVarCharValue (const CreateValueArgs& args);

	static void describeInterval (DescribeArgs& args);
	static CInformixAbstractValue * createIntervalValue (const CreateValueArgs& args);

	static void describeInt8 (DescribeArgs& args);
	static CInformixAbstractValue * createInt8Value (const CreateValueArgs& args);

	static void describeSerial8 (DescribeArgs& args);
	static CInformixAbstractValue * createSerial8Value (const CreateValueArgs& args);

	static void describeVarBinary (DescribeArgs& args);
	static CInformixAbstractValue * createVarBinaryValue (const CreateValueArgs& args);

	static void describeUDTFixed (DescribeArgs& args);
	static CInformixAbstractValue * createBlobValue (const CreateValueArgs& args);
	static CInformixAbstractValue * createClobValue (const CreateValueArgs& args);

	static void describeLVarChar (DescribeArgs& args);
	static CInformixAbstractValue * createLVarCharValue (const CreateValueArgs& args);

	static void describeLVarCharPtr (DescribeArgs& args);
	static CInformixAbstractValue * createLVarCharPtrValue (const CreateValueArgs& args);

	static void describeBool (DescribeArgs& args);
	static CInformixAbstractValue * createBoolValue (const CreateValueArgs& args);

	typedef void (*DescribeFunc) (DescribeArgs& args);
	static DescribeFunc DescribeFuncTable[];
};

#endif // __IFXCURSOR_HPP__
